package network.protocol;
import java.util.Vector;

import main.Config;
import network.NetworkConstants;
import network.dataFormats.NetworkData;
import network.dataFormats.NetworkPackage;
import physics.Body;
import physics.joints.Joint;
import tools.Log;
import game.Game;
import game.engine.GSync;
import game.objects.GameObject;
import graphics.objects.GraphicsObject;
/**
 * Abstract network class. Is extended by Server/Client-Handler. A game that is initialized to be a server will have an instance of ServerHandler otherwise it will be a ClientHandler.
 * 
 * Upon adding a client to a ServerHandler, the current game state will be serialized and sent across the network where it will be de-serialized and converted into a game which is then saved in the client.
 * 
 * From that point only synchronization has to be done so the client is always up to date. Each client needs to be informed about added/removed bodies, joints, graphicsObjects, gameObjects, ... and the server will only have to receive control information from the client which is then translated into game actions, which are sent back to each client / server.
 * 
 * @author toni
 * 
 */
public abstract class NetworkHandler {
	protected Game game;
	private Vector<NetworkPackage> remember;
	private int fps;
	private int nextId = -1;
	private PackageSplitter splitter;
	public int id;
	public NetworkHandler() {
		remember = new Vector<NetworkPackage>();
		splitter = new PackageSplitter();
	}
	public abstract void handle();
	public void setGame(Game g) {
		game = g;
	}
	public void addBody(GameObject go, Body b) {
	}
	public void remBody(GameObject go, Body b) {
	}
	public void addJoint(GameObject go, Joint j) {
	}
	public void remJoint(GameObject go, Joint j) {
	}
	public void remGraphicsObject(GameObject go, GraphicsObject o) {
	}
	public void addGraphicsObject(GameObject go, GSync s, GraphicsObject o) {
	}
	public void remGameObject(GameObject go) {
	}
	public void addGameObject(GameObject go) {
	}
	/**
	 * Takes an arbitrary amount of packages and separates it into the needed amount of networkData types.
	 * 
	 * @author toni
	 * 
	 * @param packages
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected Vector<NetworkData> makeNetworkData(Vector<NetworkPackage> packages) {
		Vector<NetworkData> data = new Vector<NetworkData>();
		// Split big packages into smaller pieces so they can still be sent.
		packages = splitter.splitBigPackages(packages);
		Vector<NetworkPackage> part = new Vector<NetworkPackage>();
		int size = 0;
		for (int i = 0; i < packages.size(); i++) {
			if (part.size() == NetworkConstants.MAXNUMPACKAGES || size >= PackageSplitter.ALLOWEDSIZE) { // Reached maximum
																											// length or
																											// maximum size
																											// in bytes?
				data.add(new NetworkData((Vector<NetworkPackage>) part.clone())); // create
																					// network-data
																					// type.
				part.clear(); // clear the collection
			}
			part.add(packages.get(i));
			size += packages.get(i).getSize();
		}
		if (part.size() != 0) {
			data.add(new NetworkData((Vector<NetworkPackage>) part.clone()));
			part.clear();
		}
		for (NetworkData d : data){
			Log.n("data " + d.data.length);
		}
		return data;
	}
	@SuppressWarnings("unchecked")
	protected Vector<NetworkData> makeNetworkDataFast(Vector<NetworkPackage> packages) {
		Vector<NetworkData> data = new Vector<NetworkData>();
		// Split big packages into smaller pieces so they can still be sent.
		Vector<NetworkPackage> part = new Vector<NetworkPackage>();
		for (int i = 0; i < packages.size(); i++) {
			if (part.size() == NetworkConstants.MAXNUMPACKAGES) { // Reached
																	// maximum
																	// length or
																	// maximum
																	// size in
																	// bytes?
				data.add(new NetworkData((Vector<NetworkPackage>) part.clone())); // create
																					// network-data
																					// type.
				part.clear(); // clear the collection
			}
			part.add(packages.get(i));
		}
		if (part.size() != 0) {
			data.add(new NetworkData((Vector<NetworkPackage>) part.clone()));
			part.clear();
		}
		return data;
	}
	/**
	 * Converts a list of NetworkData objects in one large list of network packages
	 */
	protected Vector<NetworkPackage> makeNetworkPackages(Vector<NetworkData> data) {
		Vector<NetworkPackage> packages = new Vector<NetworkPackage>();
		// Packages that were put aside because they could not yet be processed
		// last time must now be added:
		for (NetworkPackage p : remember)
			packages.add(p);
		remember.clear();
		// Convert data into packages:
		for (int i = 0; i < data.size(); i++) {
			for (NetworkPackage p : data.get(i).packages) {
				packages.add(p);
			}
		}
		// join large packages back together.
		packages = splitter.joinSplitPackages(packages);
		return packages;
	}
	/**
	 * This method will put aside any package that should not yet be processed (because something else needs to arrive before) and add it to the package list the next time.
	 * 
	 * @author toni
	 * 
	 * @param p
	 */
	protected void pushBack(NetworkPackage p) {
		remember.add(p);
	}
	protected final int getCurrentFps() {
		return fps;
	}
	public final void setCurrentFps(int f) {
		fps = f;
	}
	public int getWantedFps() {
		return Config.MAXFPS;
	}
	public int getNextId() {
		nextId++;
		return nextId;
	}
	protected void clear() {
		splitter.clear();
	}
	public void addPlayer(int playerId) {
	}
}
